package com.xinruke.hostels.reservation.service.pms;

import com.alibaba.fastjson.JSONObject;
import com.xinruke.hostels.common.cache.ManageUserCache;
import com.xinruke.hostels.common.constants.RedisConstants;
import com.xinruke.hostels.common.constants.SysDicConstant;
import com.xinruke.hostels.common.exception.BizException;
import com.xinruke.hostels.common.mybatis.MyExample;
import com.xinruke.hostels.common.po.*;
import com.xinruke.hostels.common.po.constants.YwFangtairiqijiluConstants;
import com.xinruke.hostels.common.po.constants.YwYudingDingdanConstants;
import com.xinruke.hostels.common.po.constants.YwZhengjianxinxiConstants;
import com.xinruke.hostels.common.service.OperateLogService;
import com.xinruke.hostels.common.util.CustomSecurity;
import com.xinruke.hostels.common.util.DateCalendarUtil;
import com.xinruke.hostels.common.vo.ResultVO;
import com.xinruke.hostels.common.vo.query.EConditionOperator;
import com.xinruke.hostels.common.vo.query.QueryConditions;
import com.xinruke.hostels.reservation.interfaces.dto.pms.PersonalBookingDTO;
import com.xinruke.hostels.reservation.interfaces.dto.pms.PersonalBookingResultDTO;
import com.xinruke.hostels.reservation.interfaces.vo.PersonalBookingRoomVO;
import com.xinruke.hostels.reservation.mapper.*;
import com.xinruke.hostels.reservation.service.GuestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.weekend.Weekend;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @ClassName PersonalRoomService
 * @CreateDate 2019/7/4
 * @Author FengXinQiang
 * @Version V1.0.0.0
 * @Decription 个人房间Service
 */
@Service
@Slf4j
public class PersonalRoomService {
    @Autowired
    YwFangjianMapper fangjianMapper;

    @Autowired
    YwFangjianleixingMapper fangjianleixingMapper;

    @Autowired
    YwFangtairiqijiluMapper fangtairiqijiluMapper;

    @Autowired
    YwYudingDingdanMapper yudingDingdanMapper;

    @Autowired
    YwYudingDingdanZixiangMapper yudingDingdanZixiangMapper;

    @Autowired
    GuestService guestService;

    @Autowired
    OperateLogService operateLogService;

    @Autowired
    private ManageUserCache manageUserCache;

    @Resource(name = "commonRedisTemplate")
    RedisTemplate commonRedisTemplate;

    /**
     * 个人房间预订
     * <p>
     * 1.Redis加锁
     * 2.保存宾客信息
     * 3.写入预订单表
     * 4.锁定房间
     * 5.写入预订单子表
     * 6.写入操作日志
     *
     * @param personalBookingDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultVO<PersonalBookingResultDTO> booking(PersonalBookingDTO personalBookingDTO) {
        String traceId = CustomSecurity.getTraceID();
        log.info("traceId[" + traceId + "]" + JSONObject.toJSONString(personalBookingDTO));

        ResultVO<PersonalBookingResultDTO> resultVO = ResultVO.fail();

        personalBookingDTO.setZhengjianhao(CustomSecurity.encodeIDCard(personalBookingDTO.getZhengjianhao()));
        personalBookingDTO.setYudingrendianhua(CustomSecurity.encodeMobile(personalBookingDTO.getYudingrendianhua()));

        int jiudianId = manageUserCache.getJiudianId();
        String redisLockKey = RedisConstants.HOTEL_ROOM_LOCK_KEY_PREFIX + jiudianId;
        try {
            //使用redis，根据酒店id对房间操作加锁
            boolean lockRet = commonRedisTemplate.opsForValue().setIfAbsent(redisLockKey, jiudianId);
            if (!lockRet) {
                log.error("traceId[" + traceId + "]房间冲突，请重试");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                resultVO.setMessage("房间冲突，请重试");
                return resultVO;
            }

            String dingdanhao = YwYudingDingdanConstants.DINGDANHAO_PREFIX + System.currentTimeMillis();

            //保存宾客信息
            YwZhengjianxinxi zhengjianxinxi = new YwZhengjianxinxi();
            zhengjianxinxi.setShoujihao(personalBookingDTO.getYudingrendianhua());
            zhengjianxinxi.setXingming(personalBookingDTO.getYudingrenxingming());
            zhengjianxinxi.setZhengjianhao(personalBookingDTO.getZhengjianhao());
            zhengjianxinxi.setZhengjianleixing(personalBookingDTO.getZhengjianleixing());
            zhengjianxinxi.setJiudianId(jiudianId);
            zhengjianxinxi.setYewuleixing(YwZhengjianxinxiConstants.YEWULEIXING_QIANTAIYUDINGDAN);
            zhengjianxinxi.setYewulaiyuanId(-1);
            int guestId = guestService.saveGuest(zhengjianxinxi);

            //计算入住天数
            Calendar ruzhushijian = Calendar.getInstance();
            ruzhushijian.setTime(personalBookingDTO.getRuzhushijian());
            ruzhushijian.set(Calendar.HOUR,0);
            ruzhushijian.set(Calendar.MINUTE,0);
            ruzhushijian.set(Calendar.SECOND,0);
            Calendar likaishijian = Calendar.getInstance();
            likaishijian.setTime(personalBookingDTO.getLikaishijian());
            likaishijian.set(Calendar.HOUR,0);
            likaishijian.set(Calendar.MINUTE,0);
            likaishijian.set(Calendar.SECOND,0);
            BigDecimal days = BigDecimal.valueOf(DateCalendarUtil.getDiffDays(ruzhushijian.getTime(),likaishijian.getTime()));
            //计算总金额
            double youhuijineTotal = 0;
            double dingdanzongjiaTotal = 0;
            List<PersonalBookingRoomVO> roomVOList = personalBookingDTO.getRoomVOList();
            for (PersonalBookingRoomVO roomVO : roomVOList) {
                int fangjianid = roomVO.getFangjianId();
                //根据房间id，获取房间信息
                YwFangjian fangjian = fangjianMapper.selectByPrimaryKey(fangjianid);
                if (fangjian == null || fangjian.getShanchubiaoshi() != SysDicConstant.DELFLAG_0) {
                    log.error("traceId[" + traceId + "]房间[" + fangjianid + "]不可用");
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    resultVO.setMessage("房间[" + fangjianid + "]不可用");
                    return resultVO;
                }

                //根据房型id，获取房型信息
                int fangxingid = fangjian.getFangxingId();
                YwFangjianleixing fangjianleixing = fangjianleixingMapper.selectByPrimaryKey(fangxingid);

                double youhuijia = roomVO.getYouhuijia().multiply(days).doubleValue();
                double mendianjia = fangjianleixing.getMendianjia().multiply(days).doubleValue();
                dingdanzongjiaTotal = dingdanzongjiaTotal + youhuijia;
                youhuijineTotal = youhuijineTotal + (mendianjia - youhuijia);
            }

            //写入预订单表
            YwYudingDingdan ywYudingDingdan = new YwYudingDingdan();
            ywYudingDingdan.setJiudianId(jiudianId);
            ywYudingDingdan.setHuiyuanId(-1);
            ywYudingDingdan.setDingdanhao(dingdanhao);
            ywYudingDingdan.setYudingrenxingming(personalBookingDTO.getYudingrenxingming());
            ywYudingDingdan.setYudingrendianhua(personalBookingDTO.getYudingrendianhua());
            ywYudingDingdan.setZhengjianleixing(personalBookingDTO.getZhengjianleixing());
            ywYudingDingdan.setZhengjianhao(personalBookingDTO.getZhengjianhao());
            ywYudingDingdan.setYudingrenshenfenId(guestId);
            ywYudingDingdan.setRuzhushijian(personalBookingDTO.getRuzhushijian());
            ywYudingDingdan.setLikaishijian(personalBookingDTO.getLikaishijian());
            ywYudingDingdan.setBaoliushijian(personalBookingDTO.getBaoliushijian());
            ywYudingDingdan.setRuzhuleixing(personalBookingDTO.getRuzhuleixing());
            ywYudingDingdan.setKeyuanleixing(YwYudingDingdanConstants.KEYUANLEIXING_SANKE);
            ywYudingDingdan.setYudingleixing(YwYudingDingdanConstants.YUDINGLEIXING_GEREN);
            ywYudingDingdan.setLaiyuan(YwYudingDingdanConstants.LAIYUAN_QIANTAI);
            ywYudingDingdan.setYudingfangjianshu(roomVOList.size());
            ywYudingDingdan.setZhuangtai(YwYudingDingdanConstants.ZHUANGTAI_YITIJIAO);
            ywYudingDingdan.setPingjiazhuangtai(YwYudingDingdanConstants.PINGJIAZHUANGTAI_WEIPINGJIA);
            ywYudingDingdan.setYouhuijine(new BigDecimal(youhuijineTotal));
            ywYudingDingdan.setDingdanzongjia(new BigDecimal(dingdanzongjiaTotal));
            ywYudingDingdan.setYudingriqi(new Date());
            ywYudingDingdan.setChuangjianshijian(new Date());
            ywYudingDingdan.setGengxinshijian(new Date());
            ywYudingDingdan.setShanchubiaoshi(SysDicConstant.DELFLAG_0);
            ywYudingDingdan.setBeizhu(personalBookingDTO.getBeizhu());

            int dingdanRet = yudingDingdanMapper.insertSelective(ywYudingDingdan);
            if (dingdanRet <= 0) {
                log.error("traceId[" + traceId + "]写入预订单失败");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                resultVO.setMessage("写入预订单失败");
                return resultVO;
            }

            //订单Id
            int dingdanId = ywYudingDingdan.getId();
            Date kaishishijian = personalBookingDTO.getRuzhushijian();
            Date jieshushijian = personalBookingDTO.getLikaishijian();

            //根据选择的预抵时间、预离时间、房间，锁定房间
            for (PersonalBookingRoomVO roomVO : roomVOList) {
                int fangjianid = roomVO.getFangjianId();

                //根据房间id，获取房间信息
                YwFangjian fangjian = fangjianMapper.selectByPrimaryKey(fangjianid);

                int fangxingid = fangjian.getFangxingId();
                YwFangjianleixing fangjianleixing = fangjianleixingMapper.selectByPrimaryKey(fangxingid);

                //判断该房间是否被占用
                QueryConditions fangtairiqijiluQueryConditions = new QueryConditions();
                fangtairiqijiluQueryConditions.addCondition("jiudianId", EConditionOperator.EQULS, jiudianId);
                fangtairiqijiluQueryConditions.addCondition("fangjianId", EConditionOperator.EQULS, fangjianid);
                fangtairiqijiluQueryConditions.addCondition("shanchubiaoshi", EConditionOperator.EQULS, SysDicConstant.DELFLAG_0);
                fangtairiqijiluQueryConditions.addCondition("fangjianleibie", EConditionOperator.EQULS, YwFangtairiqijiluConstants.FANGJIANLEIBIE_FANGJIAN);
                MyExample fangtairiqijiluMyExample = new MyExample(YwFangtairiqijilu.class, fangtairiqijiluQueryConditions);

                QueryConditions shijianQueryConditions = new QueryConditions();
                shijianQueryConditions.addCondition("kaishishijian", kaishishijian, jieshushijian);
                shijianQueryConditions.addCondition("jieshushijian", kaishishijian, jieshushijian);
                Weekend weekend = fangtairiqijiluMyExample.createOrWeekend(YwFangtairiqijilu.class, shijianQueryConditions);
                weekend.and(fangtairiqijiluMyExample.getOredCriteria().get(0));

                List<YwFangtairiqijilu> fangtairiqijiluList = fangtairiqijiluMapper.selectByExample(weekend);

                if (!CollectionUtils.isEmpty(fangtairiqijiluList)) {
                    log.error("traceId[" + traceId + "]房间[" + fangjian.getFangjianbianhao() + "]已占用");
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    resultVO.setMessage("房间[" + fangjian.getFangjianbianhao() + "]已占用");
                    return resultVO;
                } else {
                    YwFangtairiqijilu fangtairiqijilu = new YwFangtairiqijilu();
                    fangtairiqijilu.setJiudianId(jiudianId);
                    fangtairiqijilu.setFangjianId(fangjianid);
                    fangtairiqijilu.setKaishishijian(kaishishijian);
                    fangtairiqijilu.setJieshushijian(jieshushijian);
                    fangtairiqijilu.setFangjianzhuangtai(YwFangtairiqijiluConstants.FANGJIANZHUANGTAI_SUOFANG);
                    fangtairiqijilu.setFangjianleibie(YwFangtairiqijiluConstants.FANGJIANLEIBIE_FANGJIAN);
                    fangtairiqijilu.setYewuyuanId(dingdanId);
                    fangtairiqijilu.setYewuleixing(YwFangtairiqijiluConstants.YEWULEIXING_QIANTAIYUDINGDAN);
                    fangtairiqijilu.setZhuangtai(YwFangtairiqijiluConstants.ZHUANGTAI_YOUXIAO);
                    fangtairiqijilu.setCaozuobiaoshi(YwFangtairiqijiluConstants.CAOZUOBIAOSHI_YUDINGSUOFANG);
                    fangtairiqijilu.setBeizhu("预订锁房");
                    fangtairiqijilu.setChuangjianshijian(new Date());
                    fangtairiqijilu.setGengxinshijian(new Date());
                    fangtairiqijilu.setShanchubiaoshi(SysDicConstant.DELFLAG_0);
                    int fangtaiRet = fangtairiqijiluMapper.insertSelective(fangtairiqijilu);
                    if (fangtaiRet <= 0) {
                        log.error("traceId[" + traceId + "]写入房态日期记录失败");
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        resultVO.setMessage("写入房态日期记录失败");
                        return resultVO;
                    }

                    //写入预订单子表
                    YwYudingDingdanZixiang yudingDingdanZixiang = new YwYudingDingdanZixiang();
                    yudingDingdanZixiang.setJiudianId(jiudianId);
                    yudingDingdanZixiang.setDingdanId(dingdanId);
                    yudingDingdanZixiang.setDingdanhao(dingdanhao);
                    yudingDingdanZixiang.setFangxingId(fangxingid);
                    yudingDingdanZixiang.setFangxingmingcheng(fangjianleixing.getFangxingmingcheng());
                    yudingDingdanZixiang.setFangjianId(fangjianid);
                    yudingDingdanZixiang.setFangjianhao(fangjian.getFangjianbianhao());
                    yudingDingdanZixiang.setShuliang(-1);
                    yudingDingdanZixiang.setYudingxingming(personalBookingDTO.getYudingrenxingming());
                    yudingDingdanZixiang.setYudingrenzhengjianleixing(personalBookingDTO.getZhengjianleixing());
                    yudingDingdanZixiang.setYudingrenzhengjianhao(personalBookingDTO.getZhengjianhao());
                    yudingDingdanZixiang.setYudingrenshenfenId(guestId);
                    yudingDingdanZixiang.setLianxidianhua(personalBookingDTO.getYudingrendianhua());
                    yudingDingdanZixiang.setMendianjia(fangjianleixing.getMendianjia());
                    yudingDingdanZixiang.setYouhuijia(roomVO.getYouhuijia());
                    yudingDingdanZixiang.setRuzhuxingzhi(roomVO.getRuzhuxingzhi());
                    yudingDingdanZixiang.setRuzhushijian(kaishishijian);
                    yudingDingdanZixiang.setLikaishijian(jieshushijian);
                    yudingDingdanZixiang.setChuangjianshijian(new Date());
                    yudingDingdanZixiang.setGengxinshijian(new Date());
                    yudingDingdanZixiang.setShanchubiaoshi(SysDicConstant.DELFLAG_0);
                    yudingDingdanZixiang.setShifouyouhui(false);
                    yudingDingdanZixiang.setRuzhutianshu(days.intValue());

                    int zixiangRet = yudingDingdanZixiangMapper.insertSelective(yudingDingdanZixiang);

                    //如果写入失败，手动回滚事务
                    if (zixiangRet <= 0) {
                        log.error("traceId[" + traceId + "]写入预订单子表失败");
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        resultVO.setMessage("写入预订单子表失败");
                        return resultVO;
                    }
                }
            }

            //写入操作日志
            YewuyonghuCaozuoRizhi yewuyonghuCaozuoRizhi = new YewuyonghuCaozuoRizhi("预订", "个人预订", "订单号[" + dingdanhao + "]");
            operateLogService.writeOperateLog(yewuyonghuCaozuoRizhi);

            PersonalBookingResultDTO personalBookingResultDTO = new PersonalBookingResultDTO();
            personalBookingResultDTO.setDingdanId(dingdanId);
            personalBookingResultDTO.setDingdanhao(dingdanhao);

            resultVO.setCode(ResultVO.SUCCESS);
            resultVO.setMessage("预订成功");
            resultVO.setData(personalBookingResultDTO);
        } catch (Exception e) {
            log.error("traceId[" + traceId + "]预订失败，系统异常", e);
            throw new BizException("预订失败，系统异常");
        } finally {
            commonRedisTemplate.delete(redisLockKey);
        }

        return resultVO;
    }


}
